package web.service.impl;


import org.apache.poi.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import web.common.CutPageBean;
import web.common.Result;
import web.dao.KbaseDao;
import web.entity.*;
import web.entity.UserDo;
import web.entity.admin.log.LoginDo;
import web.entity.admin.user.DownloadsEntity;
import web.entity.admin.user.ResetPwdDo;
import web.mapper.UserMysqlMapper;
import web.service.UserService;
import web.utils.RandomUtils;
import web.utils.ReUtils;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * Description:
 *
 * @author BaiGe
 * @date: 2022/4/19 10:31
 * @Version 1.0
 */
@Service
public class UserServiceImpl implements UserService {
    @Resource(name = "kbase123")
    private KbaseDao kbaseDao;


    @Autowired
    private UserMysqlMapper userMysqlMapper;

    @Override
    public User2 kbase(Long id) {
        return kbaseDao.kbase(id);
    }

    @Override
    public List<CodeTree> getTree() {
        return kbaseDao.getTree();
    }

    /***********************************************************/
    @Value("${admin.pwdDefault}")
    private String pwdDefault;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    AuthenticationManager authenticationManager;


    @Override
    public CutPageBean<HashMap<String, Object>> list(UserVo vo) {
        List<HashMap<String, Object>> res = userMysqlMapper.list(vo);
        Integer totalCount = userMysqlMapper.totalCount(vo);
        CutPageBean<HashMap<String, Object>> cutPage = new CutPageBean<>();
        cutPage.initCutPage(totalCount, vo.getPageSize(), res);
        return cutPage;
    }

    @Override
    public CutPageBean<HashMap<String, Object>> list_org_like(UserVo vo) {
        List<HashMap<String, Object>> res = userMysqlMapper.list_org_like(vo);
        Integer totalCount = userMysqlMapper.totalCount_org_like(vo);
        CutPageBean<HashMap<String, Object>> cutPage = new CutPageBean<>();
        cutPage.initCutPage(totalCount, vo.getPageSize(), res);
        return cutPage;
    }

    @Override
    public Result adminAdd(UserDo userDo) {
        Integer accountExist = userMysqlMapper.isAccountExist(userDo.getAccount());
        if (accountExist != 0) return Result.fail("帐号已存在");

        Integer phoneUnique = userMysqlMapper.isPhoneExist(userDo.getPhonenumber());
        if (phoneUnique != 0) return Result.fail("电话已存在");

        UsernamePasswordAuthenticationToken authentication =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        Security_UserDetail user = (Security_UserDetail) authentication.getPrincipal();
        UserDo admin = user.getUserDo();
        userDo.setCreate_by(admin.getAccount());

        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode(pwdDefault);
        userDo.setPassword(encode);

        userDo.setCreate_time(RandomUtils.nowStr(""));

        if (!StringUtils.hasText(userDo.getUser_type())){
            userDo.setUser_type("1");
        }

        Integer res = userMysqlMapper.adminAdd(userDo);
        if (res>0)return Result.succ("新建成功!");
        return Result.fail("新建失败!");
    }

    @Override
    public Result adminEdit(UserDo userDo) {
        //查询电话存在性
        Integer phoneUnique = userMysqlMapper.isPhoneExistExceptOne(userDo);
        if (phoneUnique != 0) return Result.fail("该电话号码已被使用");

        UsernamePasswordAuthenticationToken authentication =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        Security_UserDetail user = (Security_UserDetail) authentication.getPrincipal();
        UserDo admin = user.getUserDo();
        userDo.setUpdate_by(admin.getAccount());
        userDo.setUpdate_time(RandomUtils.nowStr(""));

        Integer res = userMysqlMapper.adminEdit(userDo);
        if (res>0){
           // Boolean clearRedis = redisTemplate.delete(userDo.getAccount());
            return Result.succ("修改成功!");
        }
        return Result.fail("修改失败!");
    }

//    @Override
////    public Result addOne(UserDo userDo) {
////        /*校验account格式*/
//////        if (!ReUtils.checkAccount(userDo.getAccount())) return Result.fail("帐号格式错误！");
////        Integer count;
////        String createdBy = "";
////        if (userDo.getId() == null) {
////            Integer accountExist = userMysqlMapper.isAccountExist(userDo.getAccount());
////            if (accountExist != 0) return Result.fail("帐号已存在");
////
////            Integer phoneUnique = userMysqlMapper.isPhoneExist(userDo.getPhonenumber());
////            if (phoneUnique != 0) return Result.fail("电话已存在");
////
////            try{
////                UsernamePasswordAuthenticationToken authentication =
////                        (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
////                Security_UserDetail user = (Security_UserDetail) authentication.getPrincipal();
////                createdBy = user.getUserDo().getAccount();
////            }catch (Exception e){
////                createdBy = "0";
////            }
////
////            userDo.setPassword(passwordEncoder.encode(userDo.getPassword()));
////            userDo.setCreate_by(createdBy);
////            userDo.setCreate_time(RandomUtils.nowStr(""));
////            count = userMysqlMapper.addUser(userDo);
////            if (count != 0) return Result.succ("创建成功!");
////            return Result.fail("创建失败!");
////        } else {
////
////            Integer phoneUnique = userMysqlMapper.isPhoneExistExceptOne(userDo);
////            if (phoneUnique != 0) return Result.fail("该电话号码已被使用");
////
////            UsernamePasswordAuthenticationToken authentication =
////                    (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
////            Security_UserDetail user = (Security_UserDetail) authentication.getPrincipal();
////            Integer userid_fromToken = user.getUserDo().getId();
////            String whoUpdate = user.getUserDo().getAccount();
////            Integer targetid = userDo.getId();
////
////            userDo.setUpdate_by(whoUpdate);
////
////
////            userDo.setUpdate_time(RandomUtils.nowStr(""));
////            count = userMysqlMapper.editUser(userDo);
////            if (count != 0) return Result.succ("修改成功!");
////            return Result.fail("修改失败!");
////        }
////    }

    /**
     * 通过自行注册方式添加用户
     * @param userDo
     * @return
     */
    @Override
    public Result selfAdd(UserDo userDo) {
        Integer accountExist = userMysqlMapper.isAccountExist(userDo.getAccount());
        if (accountExist != 0) return Result.fail("帐号已存在");

        Integer phoneUnique = userMysqlMapper.isPhoneExist(userDo.getPhonenumber());
        if (phoneUnique != 0) return Result.fail("电话已存在");

        userDo.setPassword(passwordEncoder.encode(userDo.getPassword()));
        userDo.setCreate_by("0");
        userDo.setCreate_time(RandomUtils.nowStr(""));

        Integer count = userMysqlMapper.selfAdd(userDo);
        if (count != 0) return Result.succ("注册成功!");
        return Result.fail("注册失败!");
    }

    /**
     * 用户执行修改个人信息
     * 除开sql操作的字段外,
     * 需要手动配置
     * 1. 更新时间
     * 2. 谁发起更新的
     * @param userDo
     * @return
     */
    @Override
    public Result selfEdit(UserDo userDo) {
        //获取用户account
        UsernamePasswordAuthenticationToken authentication =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        Security_UserDetail user = (Security_UserDetail) authentication.getPrincipal();
        String account = user.getUserDo().getAccount();
        userDo.setAccount(account);
        userDo.setUpdate_by(account);

        //查询电话存在性
        Integer phoneUnique = userMysqlMapper.isPhoneExistExceptOne(userDo);
        if (phoneUnique != 0) return Result.fail("该电话号码已被使用");
        //更新时间
        userDo.setUpdate_time(RandomUtils.nowStr(""));

        Integer count = userMysqlMapper.selfEdit(userDo);

        if (count != 0) {
            //更新数据到redis
            Boolean upToRedis = updateUserinfoToRedis();

            HashMap<String, String> tokenMap = new HashMap<>();
            tokenMap.put("user_name", userDo.getUser_name());

            if (upToRedis)return Result.succ(tokenMap);
            return Result.fail("缓存更新失败");
        }
        return Result.fail("修改失败!");
    }

    @Override
    public Result deleteUser(UserDo userDo) {
        UsernamePasswordAuthenticationToken authentication =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        Security_UserDetail user = (Security_UserDetail) authentication.getPrincipal();

        String account_admin = user.getUserDo().getAccount();

        userDo.setDel_time(RandomUtils.nowStr(""));
        userDo.setDelete_by(account_admin);
        Integer res = userMysqlMapper.deleteUser(userDo);
        redisTemplate.delete(userDo.getAccount());
        if (res != 0) return Result.succ("删除成功!");
        return Result.fail("删除失败!");
    }


//    @Override
//    public Result resetPwd(HashMap<String, String> map) {
//        if (!ReUtils.checkAccount(map.get("newPwd"))) return Result.fail("帐号格式错误！");
//        map.put("newPwd", DigestUtils.md5DigestAsHex(map.get("newPwd").getBytes()));
//        Integer count = userMysqlMapper.resetPwd(map);
//        if (count != 0) return Result.succ("修改成功");
//        return Result.succ("修改失败");
//    }

    @Override
    public Result resetPwd(ResetPwdDo resetPwdDo) {
        UsernamePasswordAuthenticationToken authentication =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        Security_UserDetail user = (Security_UserDetail) authentication.getPrincipal();

        String account_admin = user.getUserDo().getAccount();
        String account_target = resetPwdDo.getAccount();

        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode(resetPwdDo.getNewPwd());
        resetPwdDo.setAccount(account_target);

        resetPwdDo.setNewPwd(encode);

        resetPwdDo.setUpdate_by(account_admin);

        resetPwdDo.setUpdate_time(RandomUtils.nowStr(""));

        Integer count = userMysqlMapper.resetPwd(resetPwdDo);

        /*清空redis*/
        if (count > 0){
            //clearRedis:当用户token存在redis中时,clearRedis=true
            //当用户token过期被清除后,clearRedis=false
            Boolean clearRedis = redisTemplate.delete(account_target);
            return Result.succ("修改成功");
        }{
            return Result.fail("修改失败");
        }
    }

    @Override
    public Result basicInfo() {
        UsernamePasswordAuthenticationToken authentication =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        Security_UserDetail user = (Security_UserDetail) authentication.getPrincipal();
        HashMap<String, String> userInfo = new HashMap<>();
//        userInfo.put("id", user.getUserDo().getId().toString());
        userInfo.put("account", user.getUserDo().getAccount());
        userInfo.put("user_name", user.getUserDo().getUser_name());
        userInfo.put("phonenumber", user.getUserDo().getPhonenumber());
        userInfo.put("department", user.getUserDo().getDepartment());
        return Result.succ(userInfo);
    }

    @Override
    public Result changePwd(UserDo userDo) {
        UsernamePasswordAuthenticationToken authentication =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        Security_UserDetail user = (Security_UserDetail) authentication.getPrincipal();
        String account = user.getUserDo().getAccount();
        String encodePwd = user.getUserDo().getPassword();

        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        Boolean check = bCryptPasswordEncoder.matches(userDo.getPassword(),encodePwd);
        if (!check) return Result.fail("密码错误");

        String encode = bCryptPasswordEncoder.encode(userDo.getNew_password());
        userDo.setPassword(encode);
        userDo.setAccount(account);

        Integer changeRes = userMysqlMapper.changePwd(userDo);
        if (changeRes>0){
            if (redisTemplate.delete(account)){
                return Result.succ("密码修改成功");
            }else {
                return Result.fail("清除缓存失败");
            }
        }
        return Result.fail("密码修改失败");
    }


    private Boolean updateUserinfoToRedis(){

        UsernamePasswordAuthenticationToken authentication =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        Security_UserDetail user = (Security_UserDetail) authentication.getPrincipal();
        UserDo userDo1 = user.getUserDo();


        UserDo userDo = userMysqlMapper.getUserByAccountAndPhone(userDo1.getAccount());
        Security_UserDetail security_userDetail = new Security_UserDetail();
        security_userDetail.setUserDo(userDo);
        security_userDetail.setRoles(userDo.getRoles());

        try {
            ValueOperations valueOperations = redisTemplate.opsForValue();
            valueOperations.set(userDo.getAccount(), security_userDetail,1, TimeUnit.DAYS);
            return true;
//            redisCache.setTTL(redisPrefix + id, ss);
        } catch (Exception e) {
            e.printStackTrace();
//            redis插入值失败: ①redis服务未启用
            return false;
        }
    }


    @Override
    public CutPageBean<DownloadsEntity>  preview(Integer page,Integer pageSize,String resource_title,String create_time) {
        UsernamePasswordAuthenticationToken authentication =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        Security_UserDetail user = (Security_UserDetail) authentication.getPrincipal();
        String account_admin = user.getUserDo().getAccount();
        UserVo vo =new UserVo();
        vo.setPage(page);
        vo.setPageSize(pageSize);
        vo.setAccount(account_admin);
        vo.setStart(page,pageSize);
        vo.setResource_title(resource_title);
        vo.setCreate_time(create_time);
        List<DownloadsEntity> res = userMysqlMapper.previewList(vo);
        Integer count = userMysqlMapper.count1(vo);
        CutPageBean<DownloadsEntity> cutPage=new CutPageBean<>();
        cutPage.initCutPage(count, vo.getPageSize(), res);
        return cutPage;
    }


    @Override
    public CutPageBean<DownloadsEntity>  downloads(Integer page,Integer pageSize,String resource_title,String create_time) {
        UsernamePasswordAuthenticationToken authentication =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        Security_UserDetail user = (Security_UserDetail) authentication.getPrincipal();
        String account_admin = user.getUserDo().getAccount();
        UserVo vo =new UserVo();
        vo.setPage(page);
        vo.setPageSize(pageSize);
        vo.setAccount(account_admin);
        vo.setStart(page,pageSize);
        vo.setResource_title(resource_title);
        vo.setCreate_time(create_time);
        List<DownloadsEntity> res = userMysqlMapper.downloadsList(vo);
        Integer count = userMysqlMapper.count(vo);
        CutPageBean<DownloadsEntity> cutPage=new CutPageBean<>();
        cutPage.initCutPage(count, vo.getPageSize(), res);
        return cutPage;
    }

    @Override
    public Boolean isPhoneExist(String phone) {
        Integer phoneUnique = userMysqlMapper.isPhoneExist(phone);
        if (phoneUnique > 0) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public List<HashMap<String, Object>> getMenuListById(String id) {
        List<HashMap<String, Object>> res = userMysqlMapper.getMenuListById(id);
        return res;
    }
}
